home *** CD-ROM | disk | FTP | other *** search
/ T&A 2 the Maxx 3 / T and A 2 The Maxx Number 3.iso / viewers / unixview / xgiftar.z / xgiftar / dither.c < prev    next >
C/C++ Source or Header  |  1991-05-20  |  6KB  |  255 lines

  1. /* dither.c
  2.  *
  3.  * completely reworked dithering module for xloadimage
  4.  * uses error-diffusion dithering (floyd-steinberg) instead
  5.  * of simple 4x4 ordered-dither that was previously used
  6.  *
  7.  * the previous version of this code was written by steve losen
  8.  * (scl@virginia.edu)
  9.  * 
  10.  * jim frost    07.10.89
  11.  * Steve Losen  11.17.89
  12.  * kirk johnson 06.04.90
  13.  *
  14.  * Copyright 1990 Kirk L. Johnson (see the included file
  15.  * "kljcpyrght.h" for complete copyright information)
  16.  *
  17.  * Copyright 1989, 1990 Jim Frost and Steve Losen.
  18.  * See included file "copyright.h" for complete copyright information.
  19.  */
  20.  
  21. #include "copyright.h"
  22. #include "kljcpyrght.h"
  23. #include "image.h"
  24.  
  25. #define MaxIntensity  65536    /* maximum possible Intensity */
  26.  
  27. #define MaxGrey       32768    /* limits on the grey levels used */
  28. #define Threshold     16384    /* in the dithering process */
  29. #define MinGrey           0
  30.  
  31. static unsigned int tone_scale_adjust();
  32. static void         LeftToRight();
  33. static void         RightToLeft();
  34.  
  35.  
  36. /*
  37.  * simple floyd-steinberg dither with serpentine raster processing
  38.  */
  39.  
  40. Image *dither(cimage, verbose)
  41.      Image        *cimage;
  42.      unsigned int  verbose;
  43. {
  44.   Image          *image;    /* destination image */
  45.   unsigned int   *grey;        /* grey map for source image */
  46.   unsigned int    spl;        /* source pixel length in bytes */
  47.   unsigned int    dll;        /* destination line length in bytes */
  48.   unsigned char  *src;        /* source data */
  49.   unsigned char  *dst;        /* destination data */
  50.   int            *curr;        /* current line buffer */
  51.   int            *next;        /* next line buffer */
  52.   int            *swap;        /* for swapping line buffers */
  53.   Pixel           color;    /* pixel color */
  54.   unsigned int    level;    /* grey level */
  55.   unsigned int    i, j;        /* loop counters */
  56.  
  57.   /*
  58.    * check the source image
  59.    */
  60.   goodImage(cimage, "dither");
  61.   if (BITMAPP(cimage))
  62.     return(NULL);
  63.  
  64.   /*
  65.    * allocate destination image
  66.    */
  67.   if (verbose)
  68.   {
  69.     printf("  Dithering image...");
  70.     fflush(stdout);
  71.   }
  72.   image = newBitImage(cimage->width, cimage->height);
  73.   if (cimage->title)
  74.   {
  75.     image->title = (char *)lmalloc(strlen(cimage->title) + 12);
  76.     sprintf(image->title, "%s (dithered)", cimage->title);
  77.   }
  78.  
  79.   /*
  80.    * if the number of entries in the colormap isn't too large, compute
  81.    * the grey level for each entry and store it in grey[]. else the
  82.    * grey levels will be computed on the fly.
  83.    */
  84.   if (RGBP(cimage) && (cimage->depth <= 16))
  85.   {
  86.     grey = (unsigned int *)lmalloc(sizeof(unsigned int) * cimage->rgb.used);
  87.     for (i=0; i<cimage->rgb.used; i++)
  88.       grey[i]=
  89.     (colorIntensity(cimage->rgb.red[i],
  90.             cimage->rgb.green[i],
  91.             cimage->rgb.blue[i]) >> 1);
  92.  
  93.     for (i=0; i<cimage->rgb.used; i++)
  94.       grey[i] = tone_scale_adjust(grey[i]);
  95.   }
  96.   else
  97.   {
  98.     grey = NULL;
  99.   }
  100.  
  101.   /*
  102.    * dither setup
  103.    */
  104.   spl = cimage->pixlen;
  105.   dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
  106.   src = cimage->data;
  107.   dst = image->data;
  108.  
  109.   curr  = (int *)lmalloc(sizeof(int) * (cimage->width + 2));
  110.   next  = (int *)lmalloc(sizeof(int) * (cimage->width + 2));
  111.   curr += 1;
  112.   next += 1;
  113.   for (j=0; j<cimage->width; j++)
  114.   {
  115.     curr[j] = 0;
  116.     next[j] = 0;
  117.   }
  118.  
  119.   /*
  120.    * primary dither loop
  121.    */
  122.   for (i=0; i<cimage->height; i++)
  123.   {
  124.     /* copy the row into the current line */
  125.     for (j=0; j<cimage->width; j++)
  126.     {
  127.       color = memToVal(src, spl);
  128.       src  += spl;
  129.       
  130.       if (RGBP(cimage)) {
  131.     if (grey == NULL)
  132.       level =
  133.         tone_scale_adjust(colorIntensity(cimage->rgb.red[color],
  134.                          cimage->rgb.green[color],
  135.                          cimage->rgb.blue[color]) >> 1);
  136.     else
  137.       level = grey[color];
  138.       }
  139.       else {
  140.     level =
  141.       tone_scale_adjust(colorIntensity((TRUE_RED(color) << 8),
  142.                        (TRUE_GREEN(color) << 8),
  143.                        (TRUE_BLUE(color) << 8)) >> 1);
  144.       }
  145.       curr[j] += level;
  146.     }
  147.  
  148.     /* dither the current line */
  149.     if (i & 0x01)
  150.       RightToLeft(curr, next, cimage->width);
  151.     else
  152.       LeftToRight(curr, next, cimage->width);
  153.  
  154.     /* copy the dithered line to the destination image */
  155.     for (j=0; j<cimage->width; j++)
  156.       if (curr[j] < Threshold)
  157.     dst[j / 8] |= 1 << (7 - (j & 7));
  158.     dst += dll;
  159.     
  160.     /* circulate the line buffers */
  161.     swap = curr;
  162.     curr = next;
  163.     next = swap;
  164.     for (j=0; j<cimage->width; j++)
  165.       next[j] = 0;
  166.   }
  167.  
  168.   /*
  169.    * clean up
  170.    */
  171.   lfree((byte *)grey);
  172.   lfree((byte *)(curr-1));
  173.   lfree((byte *)(next-1));
  174.   if (verbose)
  175.     printf("done\n");
  176.   
  177.   return(image);
  178. }
  179.  
  180.  
  181. /*
  182.  * a _very_ simple tone scale adjustment routine. provides a piecewise
  183.  * linear mapping according to the following:
  184.  *
  185.  *      input:          output:
  186.  *     0 (MinGrey)    0 (MinGrey)
  187.  *     Threshold      Threshold/2
  188.  *     MaxGrey        MaxGrey
  189.  * 
  190.  * this should help things look a bit better on most displays.
  191.  */
  192. static unsigned int tone_scale_adjust(val)
  193.      unsigned int val;
  194. {
  195.   unsigned int rslt;
  196.   
  197.   if (val < Threshold)
  198.     rslt = val / 2;
  199.   else
  200.     rslt = (((val - Threshold) * (MaxGrey-(Threshold/2))) /
  201.         (MaxGrey-Threshold)) + (Threshold/2);
  202.  
  203.   return rslt;
  204. }
  205.  
  206.  
  207. /*
  208.  * dither a line from left to right
  209.  */
  210. static void LeftToRight(curr, next, width)
  211.      int *curr;
  212.      int *next;
  213.      int  width;
  214. {
  215.   int idx;
  216.   int error;
  217.   int output;
  218.  
  219.   for (idx=0; idx<width; idx++)
  220.   {
  221.     output       = (curr[idx] > Threshold) ? MaxGrey : MinGrey;
  222.     error        = curr[idx] - output;
  223.     curr[idx]    = output;
  224.     next[idx-1] += error * 3 / 16;
  225.     next[idx]   += error * 5 / 16;
  226.     next[idx+1] += error * 1 / 16;
  227.     curr[idx+1] += error * 7 / 16;
  228.   }
  229. }
  230.  
  231.  
  232. /*
  233.  * dither a line from right to left
  234.  */
  235. static void RightToLeft(curr, next, width)
  236.      int *curr;
  237.      int *next;
  238.      int  width;
  239. {
  240.   int idx;
  241.   int error;
  242.   int output;
  243.  
  244.   for (idx=(width-1); idx>=0; idx--)
  245.   {
  246.     output       = (curr[idx] > Threshold) ? MaxGrey : MinGrey;
  247.     error        = curr[idx] - output;
  248.     curr[idx]    = output;
  249.     next[idx+1] += error * 3 / 16;
  250.     next[idx]   += error * 5 / 16;
  251.     next[idx-1] += error * 1 / 16;
  252.     curr[idx-1] += error * 7 / 16;
  253.   }
  254. }
  255.